using System;
using System.Collections.Generic;
using System.Threading;
using System.Diagnostics;
using Tao.Sdl;
using Tao.DevIl;
using Tao.OpenGl;

namespace Dida
{
	public static class SdlBinding
	{
		static UnmanagedResourceCategory unmanagedResourcesCat = null;

		public static void Init(int windowWidth,int windowHeight)
		{
			unmanagedResourcesCat = UnmanagedResourceManager.CreateCategory();

			// init sdl
			int error = Sdl.SDL_Init(Sdl.SDL_INIT_VIDEO);
			if (error != 0)
				throw new Exception("Couldn't initialize sdl");

			Sdl.SDL_GL_SetAttribute(Sdl.SDL_GL_DOUBLEBUFFER, 1);
			Sdl.SDL_GL_SetAttribute(Sdl.SDL_GL_STENCIL_SIZE, 1);
			Sdl.SDL_GL_SetAttribute(Sdl.SDL_GL_DEPTH_SIZE, 16);
			Sdl.SDL_WM_SetCaption("Dida", null);
			Sdl.SDL_SetVideoMode(windowWidth,windowHeight, 32, Sdl.SDL_HWSURFACE | Sdl.SDL_OPENGL);

			Gl.glEnable(Gl.GL_DEPTH_TEST);

#if DEBUG
			// for some weird reason, the assert box doesn't show up when OpenGl is active
			// (nor does a normal message box btw), so we kill Sdl right before we have 
			// an assert.
			Debug.Listeners.Insert(0, new KillSdlOnAssert());
#endif

			Il.ilInit();

			OpenGLDebugMeshImpl.Init();
			Dbg.DebugDraw.Implementation = new OpenGLDebugDrawImpl();
		}

		public static void Free()
		{
			UnmanagedResourceManager.FreeCategory(unmanagedResourcesCat);
			unmanagedResourcesCat = null;

			// shutdown tao stuff
			Il.ilShutDown();
			Sdl.SDL_Quit();
		}

		public delegate void IdleHandler(float timeDelta);
		public static void Run(IdleHandler idleHandler)
		{
			int prevTime = Sdl.SDL_GetTicks();

			Sdl.SDL_Event evnt;
			bool done = false;
			while (!done)
			{
				if (Sdl.SDL_PollEvent(out evnt) != 0)
				{
					switch (evnt.type)
					{
						case Sdl.SDL_QUIT:
							done = true;
							break;
					}
				}
				else
				{
					UnmanagedResourceManager.Update();

					Gl.glClearColor(.5f, .5f, .5f, 0);
					Gl.glClear(Gl.GL_COLOR_BUFFER_BIT | Gl.GL_DEPTH_BUFFER_BIT |
						Gl.GL_STENCIL_BUFFER_BIT);

					int curTime = Sdl.SDL_GetTicks();
					float timeDelta = (curTime - prevTime) / 1000.0f;
					prevTime = curTime;

					if (idleHandler != null)
						idleHandler(timeDelta);

					Sdl.SDL_GL_SwapBuffers();
				}
			}
		}

		internal static UnmanagedResourceCategory UnmanagedResourceCategory
		{
			get
			{
				Debug.Assert(unmanagedResourcesCat != null);
				return unmanagedResourcesCat;
			}
		}
	}

	class KillSdlOnAssert : TraceListener
	{
		public override void Fail(string message)
		{
			Sdl.SDL_Quit();
			base.Fail(message);
		}

		public override void Fail(string message, string detailMessage)
		{
			Sdl.SDL_Quit();
			base.Fail(message, detailMessage);
		}

		public override void Write(string message)
		{
		}

		public override void WriteLine(string message)
		{
		}
	}
}